package com.kai.service.wechat.facade;

import com.google.common.collect.Lists;
import com.kai.common.util.WebUtil;
import com.kai.service.data.request.wechat.CheckRequest;
import com.kai.service.enums.WechatMsgTypeEnum;
import com.kai.service.exception.GenericException;
import com.kai.service.util.SHAUtil;
import com.kai.service.util.XmlUtil;
import com.kai.service.wechat.handle.MessageHandle;
import com.kai.service.data.dto.wechat.receive.MessageReceiveDto;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WechatFacade {

    @Autowired
    private List<MessageHandle<?>> messageHandles;

    @Value("${wechat.token:}")
    private String token;

    /**
     * 消息处理
     *
     * @param checkRequest
     * @return
     */
    public Object messageHandle(CheckRequest checkRequest, String xmlStr) {
        String method = WebUtil.getRequest().getMethod();
        // token验证
        this.checkToken(checkRequest);
        if (Objects.equals(method, HttpMethod.GET.name())) {
            return checkRequest.getEchostr();
        }

        // 获取消息类型，根据消息类型转换为对应的消息对象
        Element element = XmlUtil.xmlStrToElement(xmlStr);
        String msgType = element.element("MsgType").getText();
        Class<? extends MessageReceiveDto> messageClass = WechatMsgTypeEnum.getMessageClass(msgType);
        MessageReceiveDto messageReceiveDto = XmlUtil.xmlStrToObject(xmlStr, messageClass);

        return messageHandle(messageReceiveDto);
    }

    /**
     * 消息处理
     *
     * @param messageReceiveDto
     * @return
     */
    private Object messageHandle(MessageReceiveDto messageReceiveDto) {
        for (MessageHandle<?> messageHandle : messageHandles) {
            Type genericSuperclass = messageHandle.getClass().getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType)genericSuperclass;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                Class<?> clazz = (Class<?>)actualTypeArguments[0];

                if (clazz.isInstance(messageReceiveDto)) {
                    return messageHandle.messageAnalysisEntrance(messageReceiveDto);
                }
            }
        }

        return Boolean.TRUE;
    }

    /**
     * token校验
     *
     * @param checkRequest
     * @return
     */
    private void checkToken(CheckRequest checkRequest) {
        List<String> list = Lists.newArrayList();
        list.add(checkRequest.getTimestamp());
        list.add(checkRequest.getNonce());
        list.add(token);

        String str = list.stream().sorted().collect(Collectors.joining());
        String sha1 = SHAUtil.getSHA1(str);
        if (!Objects.equals(sha1, checkRequest.getSignature())) {
            throw new GenericException("签名校验失败");
        }
    }
}
